package struts.servlet;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;

import struts.annotation.ResponseBody;
import struts.factory.Bean;
import struts.factory.BeanFactory;
import struts.util.FastjsonUtil;
import struts.xml.XMLFactory;

public class DispatcherServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	public static final String BEANS = "BEAN";

	public String charset;

	public DispatcherServlet() {
		super();
	}

	public void destroy() {
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	@SuppressWarnings("unchecked")
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {

			String path = getPath(request);
			Map<String, Bean> map = (Map<String, Bean>) this.getServletContext().getAttribute(BEANS);
			String result = service(request, response, map, path);
			if (!StringUtils.isBlank(result)) {
				request.getRequestDispatcher(result).forward(request, response);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void init() throws ServletException {
		ServletContext servletContext = this.getServletContext();
		String root = servletContext.getRealPath("\\");
		charset = this.getInitParameter("charset");
		String contextConfigLocation = this.getInitParameter("contextConfigLocation");
		String xmlPath;
		if (StringUtils.indexOfIgnoreCase(contextConfigLocation, "classpath:") > -1) {
			contextConfigLocation = contextConfigLocation.substring(contextConfigLocation.indexOf(":") + 1);
			xmlPath = root + "WEB-INF/classes/" + contextConfigLocation;
		} else {
			xmlPath = root + contextConfigLocation;
		}
		Map<String, String> map = XMLFactory.readXml(xmlPath);
		String packagePath = map.get("base-package");
		try {
			Map<String, Bean> beans = BeanFactory.getBean(packagePath);
			servletContext.setAttribute(BEANS, beans);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private String getPath(HttpServletRequest request) {
		String servletPath = request.getServletPath();

		return servletPath.split("\\.")[0];

	}

	private String service(HttpServletRequest request, HttpServletResponse response, Map<String, Bean> map, String path) throws Exception {
		Bean bean = map.get(path);
		if (bean != null) {
			Class<?> clazz = bean.getClazz();
			Class<?>[] parameterTypes = bean.getParameterTypes();
			Object[] parameter = null;
			if (parameterTypes != null && parameterTypes.length > 0) {
				parameter = new Object[parameterTypes.length];
				for (int i = 0; i < parameterTypes.length; i++) {
					Class<?> object = parameterTypes[i];
					if (object == HttpServletRequest.class) {
						parameter[i] = request;
					} else if (object == HttpServletResponse.class) {
						parameter[i] = response;
					} else {
						parameter[i] = BeanFactory.createForm(object, request);
					}

				}
			}
			Method method = clazz.getDeclaredMethod(bean.getMethodName(), parameterTypes);
			if (bean.getReturnType() != Void.class) {
				Object result = method.invoke(clazz.newInstance(), parameter);
				if (method.isAnnotationPresent(ResponseBody.class)) {
					ResponseBody responseBody = method.getAnnotation(ResponseBody.class);
					String[] exclude = responseBody.excludes();
					String[] include = responseBody.includes();
					include = (include != null && include.length == 1 && StringUtils.isBlank(include[0])) ? null : include;
					exclude = (exclude != null && exclude.length == 1 && StringUtils.isBlank(exclude[0])) ? null : exclude;
					FastjsonUtil jsonUtil = new FastjsonUtil();
					jsonUtil.setRequest(request);
					jsonUtil.setResponse(response);
					jsonUtil.writeJsonByFilter(result, include, exclude);
					return null;
				}

				String results = (String) result;
				if (StringUtils.indexOfIgnoreCase(results, "forward:") > -1) {
					results=results.substring(results.indexOf(":") + 1);
					results=service(request, response, map, results);
				}

				return results;
			} else {
				return null;
			}
		} else {
			return path;
		}

	}
}
